package com.note.app.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.note.app.document.CollaborationOperationContent;
import com.note.app.document.NoteContent;
import com.note.app.dto.collaboration.CollaborationOperationDTO;
import com.note.app.dto.collaboration.CollaborationParticipantDTO;
import com.note.app.dto.collaboration.CollaborationSessionDTO;
import com.note.app.mapper.CollaborationOperationMapper;
import com.note.app.mapper.CollaborationParticipantMapper;
import com.note.app.mapper.CollaborationSessionMapper;
import com.note.app.mapper.NoteMapper;
import com.note.app.repository.CollaborationOperationContentRepository;
import com.note.app.repository.NoteContentRepository;
import com.note.app.service.CollaborationService;
import com.note.app.service.NoteService;
import com.note.app.service.UserService;
import com.note.common.domain.CollaborationOperation;
import com.note.common.domain.CollaborationParticipant;
import com.note.common.domain.CollaborationSession;
import com.note.common.domain.Note;
import com.note.common.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 协作服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CollaborationServiceImpl implements CollaborationService {

    private final CollaborationSessionMapper sessionMapper;
    private final CollaborationParticipantMapper participantMapper;
    private final CollaborationOperationMapper operationMapper;
    private final CollaborationOperationContentRepository operationContentRepository;
    private final NoteMapper noteMapper;
    private final NoteContentRepository noteContentRepository;
    private final UserService userService;
    private final NoteService noteService;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ObjectMapper objectMapper;

    // Redis键前缀
    private static final String SESSION_KEY_PREFIX = "collaboration:session:";
    private static final String PARTICIPANT_KEY_PREFIX = "collaboration:participant:";
    private static final String COLORS = "#FF5733,#33FF57,#3357FF,#F033FF,#FF33A8,#33FFF6,#FFF033,#FF8C33";

    @Override
    @Transactional
    public CollaborationSessionDTO createSession(Long userId, Long noteId, String name) {
        // 验证笔记是否存在
        Note note = noteMapper.selectById(noteId);
        if (note == null) {
            throw new BusinessException("笔记不存在");
        }

        // 验证用户是否有权限创建会话
        if (!note.getUserId().equals(userId)) {
            throw new BusinessException("无权限创建会话");
        }

        // 创建会话
        CollaborationSession session = new CollaborationSession();
        session.setNoteId(noteId);
        session.setCreatorId(userId);
        session.setName(StringUtils.hasText(name) ? name : note.getTitle() + "的协作会话");
        session.setAccessToken(generateAccessToken());
        session.setStatus(1); // 1-活跃
        session.setMaxParticipants(10); // 默认最多10人
        session.setExpiredAt(LocalDateTime.now().plusDays(7)); // 默认7天过期

        // 设置会话的创建时间
        session.setCreatedAt(LocalDateTime.now());
        session.setUpdatedAt(LocalDateTime.now());

        sessionMapper.insert(session);

        // 添加创建者为参与者
        CollaborationParticipant participant = new CollaborationParticipant();
        participant.setSessionId(session.getId());
        participant.setUserId(userId);
        participant.setRole(2); // 2-管理员
        participant.setColor(getRandomColor());
        participant.setIsOnline(1); // 1-在线
        participant.setCursorPosition("{}");
        participant.setCreatedAt(LocalDateTime.now());
        participant.setUpdatedAt(LocalDateTime.now());
        participantMapper.insert(participant);

        // 初始化操作内容
        initializeSessionContent(session.getId(), noteId, userId);

        // 返回会话信息
        return getSessionInfo(session.getId());
    }

    @Override
    @Transactional
    public boolean closeSession(Long sessionId, Long userId) {
        // 验证会话是否存在
        CollaborationSession session = sessionMapper.selectById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }

        // 验证用户是否有权限关闭会话
        CollaborationParticipant participant = participantMapper.selectBySessionIdAndUserId(sessionId, userId);
        if (participant == null || participant.getRole() < 2) {
            throw new BusinessException("无权限关闭会话");
        }

        // 更新会话状态
        session.setStatus(0); // 0-关闭
        sessionMapper.updateById(session);

        // 清理Redis缓存
        redisTemplate.delete(SESSION_KEY_PREFIX + sessionId);

        return true;
    }

    @Override
    @Transactional
    public CollaborationParticipantDTO joinSession(Long sessionId, Long userId, String accessToken) {
        // 验证会话是否存在
        CollaborationSession session = sessionMapper.selectById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }

        // 验证会话是否活跃
        if (session.getStatus() != 1) {
            throw new BusinessException("会话已关闭");
        }

        // 验证访问令牌
        if (!session.getAccessToken().equals(accessToken)) {
            throw new BusinessException("访问令牌无效");
        }

        // 验证会话是否超过最大参与人数
        int participantCount = participantMapper.countBySessionId(sessionId);
        if (participantCount >= session.getMaxParticipants()) {
            throw new BusinessException("会话已达到最大参与人数");
        }

        // 检查用户是否已经是参与者
        CollaborationParticipant participant = participantMapper.selectBySessionIdAndUserId(sessionId, userId);
        if (participant == null) {
            // 新参与者，添加记录
            participant = new CollaborationParticipant();
            participant.setSessionId(sessionId);
            participant.setUserId(userId);
            participant.setRole(1); // 1-编辑者
            participant.setColor(getRandomColor());
            participant.setIsOnline(1); // 1-在线
            participant.setCursorPosition("{}");
            participant.setCreatedAt(LocalDateTime.now());
            participant.setUpdatedAt(LocalDateTime.now());
            participantMapper.insert(participant);
        } else {
            // 更新在线状态
            participant.setIsOnline(1);
            participant.setUpdatedAt(LocalDateTime.now());
            participantMapper.updateById(participant);
        }

        // 更新Redis缓存
        String participantKey = PARTICIPANT_KEY_PREFIX + sessionId + ":" + userId;
        safeSetToRedis(participantKey, participant, 1, TimeUnit.DAYS);

        // 转换为DTO
        CollaborationParticipantDTO dto = convertToParticipantDTO(participant);

        return dto;
    }

    @Override
    @Transactional
    public boolean leaveSession(Long sessionId, Long userId) {
        // 验证用户是否是参与者
        CollaborationParticipant participant = participantMapper.selectBySessionIdAndUserId(sessionId, userId);
        if (participant == null) {
            return false;
        }

        // 更新在线状态
        participant.setIsOnline(0); // 0-离线
        participantMapper.updateById(participant);

        // 清理Redis缓存
        String participantKey = PARTICIPANT_KEY_PREFIX + sessionId + ":" + userId;
        safeDeleteFromRedis(participantKey);

        return true;
    }

    @Override
    public CollaborationSessionDTO getSessionInfo(Long sessionId) {
        // 查询会话信息
        CollaborationSession session = sessionMapper.selectById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }

        // 查询参与者列表
        List<CollaborationParticipant> participants = participantMapper.selectBySessionId(sessionId);

        // 查询笔记信息
        Note note = noteMapper.selectById(session.getNoteId());

        // 转换为DTO
        CollaborationSessionDTO dto = new CollaborationSessionDTO();
        BeanUtils.copyProperties(session, dto);
        dto.setNoteTitle(note != null ? note.getTitle() : "未知笔记");
        dto.setCreatorName(userService.getUsernameById(session.getCreatorId()));
        dto.setCurrentParticipants(participants.size());
        dto.setParticipants(participants.stream().map(this::convertToParticipantDTO).collect(Collectors.toList()));

        return dto;
    }

    @Override
    public List<CollaborationSessionDTO> getUserSessions(Long userId) {
        // 查询用户参与的会话
        List<CollaborationSession> sessions = sessionMapper.selectUserSessions(userId);

        // 转换为DTO列表
        return sessions.stream().map(session -> {
            CollaborationSessionDTO dto = new CollaborationSessionDTO();
            BeanUtils.copyProperties(session, dto);

            // 查询笔记信息
            Note note = noteMapper.selectById(session.getNoteId());
            dto.setNoteTitle(note != null ? note.getTitle() : "未知笔记");

            // 设置创建者名称
            dto.setCreatorName(userService.getUsernameById(session.getCreatorId()));

            // 设置当前参与人数
            int participantCount = participantMapper.countBySessionId(session.getId());
            dto.setCurrentParticipants(participantCount);

            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public List<CollaborationSessionDTO> getNoteActiveSessions(Long noteId) {
        // 查询笔记的活跃会话
        List<CollaborationSession> sessions = sessionMapper.selectNoteActiveSessions(noteId);

        // 转换为DTO列表
        return sessions.stream().map(session -> {
            CollaborationSessionDTO dto = new CollaborationSessionDTO();
            BeanUtils.copyProperties(session, dto);

            // 查询笔记信息
            Note note = noteMapper.selectById(session.getNoteId());
            dto.setNoteTitle(note != null ? note.getTitle() : "未知笔记");

            // 设置创建者名称
            dto.setCreatorName(userService.getUsernameById(session.getCreatorId()));

            // 设置当前参与人数
            int participantCount = participantMapper.countBySessionId(session.getId());
            dto.setCurrentParticipants(participantCount);

            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public CollaborationOperationDTO handleOperation(Long userId, Long sessionId, int operationType, String position, String content) {
        // 验证会话是否存在
        CollaborationSession session = sessionMapper.selectById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }

        // 验证用户是否是参与者
        CollaborationParticipant participant = participantMapper.selectBySessionIdAndUserId(sessionId, userId);
        if (participant == null) {
            throw new BusinessException("不是会话参与者");
        }

        // 验证用户是否有编辑权限
        if (participant.getRole() < 1) {
            throw new BusinessException("没有编辑权限");
        }

        // 获取最新版本号
        Integer maxVersion = operationMapper.selectMaxVersionBySessionId(sessionId);
        int version = maxVersion != null ? maxVersion + 1 : 1;

        // 保存操作内容到MongoDB
        CollaborationOperationContent operationContent = new CollaborationOperationContent();
        operationContent.setSessionId(sessionId);
        operationContent.setUserId(userId);
        operationContent.setVersion(version);
        operationContent.setOpType(operationType);
        operationContent.setPosition(position);
        operationContent.setContent(content);
        operationContent.setCreatedAt(LocalDateTime.now());

        // 每10个版本保存一次完整文档快照
        if (version % 10 == 0) {
            String documentSnapshot = generateDocumentSnapshot(sessionId);
            operationContent.setDocumentSnapshot(documentSnapshot);
        }

        operationContentRepository.save(operationContent);

        // 保存操作记录到MySQL
        CollaborationOperation operation = new CollaborationOperation();
        operation.setSessionId(sessionId);
        operation.setUserId(userId);
        operation.setContentId(operationContent.getId());
        operation.setOpType(operationType);
        operation.setVersion(version);
        operation.setCreatedAt(LocalDateTime.now());
        operation.setUpdatedAt(LocalDateTime.now());
        operationMapper.insert(operation);

        // 转换为DTO
        CollaborationOperationDTO dto = new CollaborationOperationDTO();
        BeanUtils.copyProperties(operation, dto);
        dto.setUsername(userService.getUsernameById(userId));
        dto.setUserColor(participant.getColor());
        dto.setPosition(position);
        dto.setContent(content);
        dto.setCreatedAt(LocalDateTime.now());

        return dto;
    }

    @Override
    public List<CollaborationOperationDTO> getOperationHistory(Long sessionId, int limit) {
        // 查询操作历史
        List<CollaborationOperation> operations = operationMapper.selectHistoryBySessionId(sessionId, limit);

        // 转换为DTO列表
        return operations.stream().map(operation -> {
            CollaborationOperationDTO dto = new CollaborationOperationDTO();
            BeanUtils.copyProperties(operation, dto);

            // 查询用户信息
            dto.setUsername(userService.getUsernameById(operation.getUserId()));

            // 查询参与者信息获取颜色
            CollaborationParticipant participant = participantMapper.selectBySessionIdAndUserId(sessionId, operation.getUserId());
            if (participant != null) {
                dto.setUserColor(participant.getColor());
            }

            // 查询操作内容
            CollaborationOperationContent content = operationContentRepository.findBySessionIdAndVersion(sessionId, operation.getVersion());
            if (content != null) {
                dto.setPosition(content.getPosition());
                dto.setContent(content.getContent());
                dto.setCreatedAt(content.getCreatedAt());
            }

            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public boolean updateParticipantRole(Long sessionId, Long userId, Long participantId, int role) {
        // 验证会话是否存在
        CollaborationSession session = sessionMapper.selectById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }

        // 验证操作者是否是管理员
        CollaborationParticipant operator = participantMapper.selectBySessionIdAndUserId(sessionId, userId);
        if (operator == null || operator.getRole() < 2) {
            throw new BusinessException("没有管理权限");
        }

        // 查询目标参与者
        CollaborationParticipant participant = participantMapper.selectById(participantId);
        if (participant == null || !participant.getSessionId().equals(sessionId)) {
            throw new BusinessException("参与者不存在");
        }

        // 更新角色
        participant.setRole(role);
        participantMapper.updateById(participant);

        // 更新Redis缓存
        String participantKey = PARTICIPANT_KEY_PREFIX + sessionId + ":" + participant.getUserId();
        safeSetToRedis(participantKey, participant, 1, TimeUnit.DAYS);

        return true;
    }

    @Override
    public boolean updateCursorPosition(Long sessionId, Long userId, String position) {
        // 验证用户是否是参与者
        CollaborationParticipant participant = participantMapper.selectBySessionIdAndUserId(sessionId, userId);
        if (participant == null) {
            return false;
        }

        // 更新光标位置
        participant.setCursorPosition(position);
        participantMapper.updateById(participant);

        // 更新Redis缓存
        String participantKey = PARTICIPANT_KEY_PREFIX + sessionId + ":" + userId;
        safeSetToRedis(participantKey, participant, 1, TimeUnit.DAYS);

        return true;
    }

    @Override
    @Transactional
    public boolean saveToNote(Long sessionId, Long userId) {
        log.info("开始保存协作内容到笔记: sessionId={}, userId={}", sessionId, userId);
        
        // 验证会话是否存在
        CollaborationSession session = sessionMapper.selectById(sessionId);
        if (session == null) {
            log.error("会话不存在: sessionId={}", sessionId);
            throw new BusinessException("会话不存在");
        }

        // 验证用户是否有权限保存
        CollaborationParticipant participant = participantMapper.selectBySessionIdAndUserId(sessionId, userId);
        if (participant == null || participant.getRole() < 2) {
            log.error("用户没有保存权限: sessionId={}, userId={}, role={}", 
                    sessionId, userId, participant != null ? participant.getRole() : "null");
            throw new BusinessException("没有保存权限");
        }

        // 查询笔记信息
        Note note = noteMapper.selectById(session.getNoteId());
        if (note == null) {
            log.error("笔记不存在: noteId={}", session.getNoteId());
            throw new BusinessException("笔记不存在");
        }
        
        // 诊断MongoDB连接
        if (StringUtils.hasText(note.getContentId())) {
            diagnoseMongoDbConnection(note.getContentId(), note.getId());
        }

        // 获取最新版本的文档内容
        String documentContent = generateDocumentSnapshot(sessionId);
        if (!StringUtils.hasText(documentContent)) {
            // 如果无法获取协作内容，尝试从原笔记获取内容
            if (StringUtils.hasText(note.getContentId())) {
                log.warn("协作内容为空，尝试使用原笔记内容: noteId={}, contentId={}", 
                        note.getId(), note.getContentId());
                
                try {
                    Optional<NoteContent> originalContent = noteContentRepository.findById(note.getContentId());
                    log.info("MongoDB查询结果: contentId={}, isPresent={}", 
                            note.getContentId(), originalContent.isPresent());
                    
                    if (originalContent.isPresent()) {
                        NoteContent content = originalContent.get();
                        boolean hasContent = StringUtils.hasText(content.getContent());
                        log.info("原笔记内容: noteId={}, hasContent={}, contentLength={}", 
                                note.getId(), 
                                hasContent, 
                                hasContent ? content.getContent().length() : 0);
                        
                        if (hasContent) {
                            documentContent = content.getContent();
                            log.info("使用原笔记内容: contentLength={}", documentContent.length());
                        } else {
                            log.error("原笔记内容为空: contentId={}", note.getContentId());
                            throw new BusinessException("文档内容为空 - MongoDB中的内容为空");
                        }
                    } else {
                        log.error("在MongoDB中未找到笔记内容: contentId={}", note.getContentId());
                        
                        // 尝试查询所有相关内容记录
                        List<NoteContent> allNoteContent = noteContentRepository.findByNoteIdOrderByVersionDesc(note.getId());
                        if (!allNoteContent.isEmpty()) {
                            log.info("找到笔记的其他内容版本: count={}", allNoteContent.size());
                            NoteContent latestContent = allNoteContent.get(0);
                            if (StringUtils.hasText(latestContent.getContent())) {
                                log.info("使用最新版本内容: version={}, contentLength={}", 
                                        latestContent.getVersion(), latestContent.getContent().length());
                                documentContent = latestContent.getContent();
                            } else {
                                log.error("最新版本内容也为空");
                                throw new BusinessException("文档内容为空 - 所有版本内容均为空");
                            }
                        } else {
                            log.error("笔记没有任何内容版本: noteId={}", note.getId());
                            throw new BusinessException("文档内容为空 - 未找到任何内容版本");
                        }
                    }
                } catch (Exception e) {
                    if (!(e instanceof BusinessException)) {
                        log.error("MongoDB查询异常: {}", e.getMessage(), e);
                        throw new BusinessException("文档内容获取失败 - MongoDB查询异常");
                    }
                    throw e;
                }
            } else {
                log.error("文档内容为空且笔记无contentId: noteId={}", note.getId());
                throw new BusinessException("文档内容为空 - 笔记无内容ID");
            }
        }

        // 保存到笔记内容
        NoteContent noteContent;
        if (StringUtils.hasText(note.getContentId())) {
            // 更新已有内容
            log.info("更新已有笔记内容: contentId={}", note.getContentId());
            noteContent = noteContentRepository.findById(note.getContentId()).orElse(new NoteContent());
            if (noteContent.getId() == null) {
                log.warn("更新内容ID不存在，将创建新内容: contentId={}", note.getContentId());
            }
        } else {
            // 创建新内容
            log.info("创建新笔记内容");
            noteContent = new NoteContent();
            noteContent.setNoteId(note.getId());
            noteContent.setVersion(1);
            noteContent.setCreatedBy(userId);
            noteContent.setCreatedAt(LocalDateTime.now());
        }

        noteContent.setContent(documentContent);
        noteContent.setUpdatedAt(LocalDateTime.now());
        noteContent.setUpdatedBy(userId);
        
        try {
            NoteContent savedContent = noteContentRepository.save(noteContent);
            log.info("笔记内容保存成功: contentId={}, contentLength={}", 
                    savedContent.getId(), documentContent.length());
            
            // 更新笔记的内容ID
            if (!StringUtils.hasText(note.getContentId()) || !note.getContentId().equals(savedContent.getId())) {
                note.setContentId(savedContent.getId());
                noteMapper.updateById(note);
                log.info("更新笔记contentId: noteId={}, contentId={}", note.getId(), savedContent.getId());
            }
        } catch (Exception e) {
            log.error("保存到MongoDB失败: {}", e.getMessage(), e);
            throw new BusinessException("保存内容失败 - MongoDB存储异常");
        }

        return true;
    }

    /**
     * 诊断会话操作，分析是否有内容可以获取
     *
     * @param sessionId 会话ID
     */
    private void diagnoseSessionOperations(Long sessionId) {
        log.info("诊断会话操作: sessionId={}", sessionId);

        // 查询操作数量
        Integer operationCount = operationMapper.countBySessionId(sessionId);
        log.info("会话操作总数: count={}", operationCount);

        if (operationCount == 0) {
            log.warn("会话没有任何操作记录，这可能导致无法生成文档内容");
            return;
        }

        // 查询第一个操作
        CollaborationOperation firstOp = operationMapper.selectFirstBySessionId(sessionId);
        if (firstOp != null) {
            log.info("会话第一个操作: opId={}, userId={}, version={}, type={}, contentId={}",
                    firstOp.getId(), firstOp.getUserId(), firstOp.getVersion(), firstOp.getOpType(), firstOp.getContentId());

            // 检查第一个操作的内容是否存在
            if (StringUtils.hasText(firstOp.getContentId())) {
                Optional<CollaborationOperationContent> firstContent =
                        operationContentRepository.findById(firstOp.getContentId());

                if (firstContent.isPresent()) {
                    CollaborationOperationContent content = firstContent.get();
                    boolean hasContent = StringUtils.hasText(content.getContent());
                    boolean hasSnapshot = StringUtils.hasText(content.getDocumentSnapshot());

                    log.info("第一个操作内容: hasContent={}, contentLength={}, hasSnapshot={}, snapshotLength={}",
                            hasContent,
                            hasContent ? content.getContent().length() : 0,
                            hasSnapshot,
                            hasSnapshot ? content.getDocumentSnapshot().length() : 0);
                } else {
                    log.error("第一个操作的内容记录不存在: contentId={}", firstOp.getContentId());
                }
            } else {
                log.error("第一个操作没有contentId");
            }
        } else {
            log.warn("无法获取第一个操作，但操作总数不为0，这可能是数据不一致");
        }

        // 查询最后一个操作
        CollaborationOperation lastOp = operationMapper.selectLastBySessionId(sessionId);
        if (lastOp != null && !lastOp.getId().equals(firstOp.getId())) {
            log.info("会话最后一个操作: opId={}, userId={}, version={}, type={}, contentId={}",
                    lastOp.getId(), lastOp.getUserId(), lastOp.getVersion(), lastOp.getOpType(), lastOp.getContentId());
        }
    }

    /**
     * 初始化会话内容
     */
    private void initializeSessionContent(Long sessionId, Long noteId, Long userId) {
        // 查询笔记内容
        Note note = noteMapper.selectById(noteId);
        if (note == null || !StringUtils.hasText(note.getContentId())) {
            return;
        }

        // 获取笔记内容
        Optional<NoteContent> noteContentOpt = noteContentRepository.findById(note.getContentId());
        if (noteContentOpt.isEmpty() || !StringUtils.hasText(noteContentOpt.get().getContent())) {
            return;
        }

        String content = noteContentOpt.get().getContent();

        // 创建初始操作内容
        CollaborationOperationContent operationContent = new CollaborationOperationContent();
        operationContent.setSessionId(sessionId);
        operationContent.setUserId(userId);
        operationContent.setVersion(1);
        operationContent.setOpType(0); // 0-插入
        operationContent.setPosition("{\"index\":0}");
        operationContent.setContent(content);
        operationContent.setDocumentSnapshot(content);
        operationContent.setCreatedAt(LocalDateTime.now());
        operationContentRepository.save(operationContent);

        // 创建操作记录
        CollaborationOperation operation = new CollaborationOperation();
        operation.setSessionId(sessionId);
        operation.setUserId(userId);
        operation.setContentId(operationContent.getId());
        operation.setOpType(0);
        operation.setVersion(1);
        operation.setCreatedAt(LocalDateTime.now());
        operation.setUpdatedAt(LocalDateTime.now());
        operationMapper.insert(operation);
    }

    /**
     * 生成文档快照
     */
    private String generateDocumentSnapshot(Long sessionId) {
        log.info("开始生成文档快照: sessionId={}", sessionId);

        // 查询最新版本的内容
        CollaborationOperationContent latestContent = operationContentRepository.findTopBySessionIdOrderByVersionDesc(sessionId);
        if (latestContent != null) {
            log.info("找到最新版本内容: sessionId={}, version={}", sessionId, latestContent.getVersion());
            if (StringUtils.hasText(latestContent.getDocumentSnapshot())) {
                log.info("使用最新版本快照: sessionId={}, version={}", sessionId, latestContent.getVersion());
                return latestContent.getDocumentSnapshot();
            } else {
                log.warn("最新版本没有快照: sessionId={}, version={}", sessionId, latestContent.getVersion());
            }
        } else {
            log.warn("未找到任何协作内容: sessionId={}", sessionId);
        }

        // 查询最近的带有快照的版本
        List<CollaborationOperationContent> contents = operationContentRepository.findBySessionIdOrderByVersionDesc(sessionId);
        log.info("查询到历史版本数量: sessionId={}, count={}", sessionId, contents.size());

        Optional<CollaborationOperationContent> snapshotOpt = contents.stream()
                .filter(c -> StringUtils.hasText(c.getDocumentSnapshot()))
                .findFirst();

        if (snapshotOpt.isPresent()) {
            CollaborationOperationContent snapshotContent = snapshotOpt.get();
            log.info("从历史版本中找到快照: sessionId={}, version={}", sessionId, snapshotContent.getVersion());
            return snapshotContent.getDocumentSnapshot();
        } else if (!contents.isEmpty()) {
            log.warn("所有历史版本中没有快照: sessionId={}, versions={}",
                    sessionId,
                    contents.stream().map(CollaborationOperationContent::getVersion).collect(Collectors.toList()));
        }

        // 没有快照，从头构建文档内容
        StringBuilder documentBuilder = new StringBuilder();
        CollaborationOperationContent firstContent = operationContentRepository.findBySessionIdAndVersion(sessionId, 1);
        if (firstContent != null) {
            log.info("使用初始版本内容构建文档: sessionId={}, version=1, contentLength={}",
                    sessionId,
                    firstContent.getContent() != null ? firstContent.getContent().length() : 0);
            if (StringUtils.hasText(firstContent.getContent())) {
                documentBuilder.append(firstContent.getContent());
            } else {
                log.error("初始版本内容为空: sessionId={}", sessionId);
            }
        } else {
            log.error("协作会话没有初始版本内容: sessionId={}", sessionId);
        }

        String result = documentBuilder.toString();
        if (!StringUtils.hasText(result)) {
            log.error("生成的文档内容为空: sessionId={}", sessionId);
        } else {
            log.info("成功生成文档内容: sessionId={}, contentLength={}", sessionId, result.length());
        }

        return result;
    }

    /**
     * 生成访问令牌
     */
    private String generateAccessToken() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 获取随机颜色
     */
    private String getRandomColor() {
        String[] colorArray = COLORS.split(",");
        int index = new Random().nextInt(colorArray.length);
        return colorArray[index];
    }

    /**
     * 转换为参与者DTO
     */
    private CollaborationParticipantDTO convertToParticipantDTO(CollaborationParticipant participant) {
        CollaborationParticipantDTO dto = new CollaborationParticipantDTO();
        BeanUtils.copyProperties(participant, dto);

        // 设置用户信息
        dto.setUsername(userService.getUsernameById(participant.getUserId()));
        dto.setAvatar(userService.getUserAvatarById(participant.getUserId()));

        // 设置加入时间和最后活跃时间
        dto.setJoinedAt(participant.getCreatedAt());
        dto.setLastActiveTime(participant.getUpdatedAt());

        return dto;
    }

    /**
     * 从Redis缓存中获取参与者信息
     */
    private CollaborationParticipant getParticipantFromCache(Long sessionId, Long userId) {
        try {
            String participantKey = PARTICIPANT_KEY_PREFIX + sessionId + ":" + userId;
            Object cachedValue = redisTemplate.opsForValue().get(participantKey);

            if (cachedValue != null) {
                // 处理对象可能是String或其他类型的情况
                if (cachedValue instanceof String) {
                    String jsonStr = (String) cachedValue;
                    try {
                        return objectMapper.readValue(jsonStr, CollaborationParticipant.class);
                    } catch (Exception e) {
                        log.error("解析Redis缓存的参与者JSON失败: {}", e.getMessage());
                    }
                } else if (cachedValue instanceof CollaborationParticipant) {
                    return (CollaborationParticipant) cachedValue;
                } else {
                    log.warn("Redis缓存中的参与者类型不匹配: {}", cachedValue.getClass().getName());
                }
            }
        } catch (Exception e) {
            log.error("从Redis获取参与者信息失败: sessionId={}, userId={}, error={}",
                    sessionId, userId, e.getMessage());
        }

        // 缓存不存在或获取失败，从数据库读取
        return participantMapper.selectBySessionIdAndUserId(sessionId, userId);
    }

    /**
     * 安全地将数据存入Redis
     *
     * @param key     Redis键
     * @param value   要存储的值对象
     * @param timeout 超时时间
     * @param unit    时间单位
     */
    private void safeSetToRedis(String key, Object value, long timeout, TimeUnit unit) {
        try {
            if (value instanceof String) {
                redisTemplate.opsForValue().set(key, value, timeout, unit);
            } else {
                try {
                    String jsonStr = objectMapper.writeValueAsString(value);
                    redisTemplate.opsForValue().set(key, jsonStr, timeout, unit);
                } catch (Exception e) {
                    log.error("对象序列化为JSON失败: {}", e.getMessage());
                }
            }
        } catch (Exception e) {
            log.error("Redis存储失败: key={}, error={}", key, e.getMessage());
        }
    }

    /**
     * 安全地从Redis获取数据
     *
     * @param key Redis键
     * @return 存储的值，获取失败时返回null
     */
    private String safeGetFromRedis(String key) {
        try {
            Object value = redisTemplate.opsForValue().get(key);
            if (value instanceof String) {
                return (String) value;
            } else if (value != null) {
                log.warn("Redis中存储的值不是String类型: {}", value.getClass().getName());
            }
            return null;
        } catch (Exception e) {
            log.error("Redis获取失败: key={}, error={}", key, e.getMessage());
            return null;
        }
    }

    /**
     * 安全地从Redis删除数据
     *
     * @param key Redis键
     */
    private void safeDeleteFromRedis(String key) {
        try {
            redisTemplate.delete(key);
        } catch (Exception e) {
            log.error("Redis删除失败: key={}, error={}", key, e.getMessage());
        }
    }

    /**
     * 诊断MongoDB连接和文档检索
     *
     * @param contentId MongoDB中的内容ID
     * @param noteId 相关笔记ID
     */
    private void diagnoseMongoDbConnection(String contentId, Long noteId) {
        log.info("诊断MongoDB连接: contentId={}, noteId={}", contentId, noteId);
        
        try {
            // 1. 尝试直接按ID获取文档
            if (StringUtils.hasText(contentId)) {
                Optional<NoteContent> content = noteContentRepository.findById(contentId);
                log.info("直接按ID查询结果: contentId={}, 是否存在={}", 
                        contentId, content.isPresent());
                
                if (content.isPresent()) {
                    NoteContent doc = content.get();
                    log.info("文档内容信息: {}", doc);
                }
            }
            
            // 2. 尝试按笔记ID查询所有版本
            if (noteId != null) {
                List<NoteContent> allVersions = noteContentRepository.findByNoteIdOrderByVersionDesc(noteId);
                log.info("按笔记ID查询结果: noteId={}, 版本数量={}", noteId, allVersions.size());
                
                if (!allVersions.isEmpty()) {
                    for (int i = 0; i < Math.min(3, allVersions.size()); i++) {
                        log.info("版本[{}]信息: {}", i, allVersions.get(i));
                    }
                    
                    if (allVersions.size() > 3) {
                        log.info("... 总共 {} 个版本", allVersions.size());
                    }
                }
            }
            
            // 3. 尝试获取最新版本
            if (noteId != null) {
                Optional<NoteContent> latestContent = noteContentRepository.findTopByNoteIdOrderByVersionDesc(noteId);
                log.info("最新版本查询结果: noteId={}, 是否存在={}", 
                        noteId, latestContent.isPresent());
                
                if (latestContent.isPresent()) {
                    log.info("最新版本信息: {}", latestContent.get());
                }
            }
        } catch (Exception e) {
            log.error("MongoDB诊断过程发生异常: {}", e.getMessage(), e);
        }
    }
} 